package we3d.layer 
{
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.display.GradientType;
	import flash.geom.Matrix;
	import we3d.core.Camera3d;
	import we3d.core.transform.Transform3d;
	import we3d.View3d;
	import we3d.math.Vector3d;
	import we3d.math.Matrix3d;
	
	/**
	* The GradientBackdrop fills the background image of a Layer with 4 colors. 
	* The Gradient also rotate when the camera rotate to create the look of a ground and sky.
	*/
	public class GradientBackdrop extends SolidBackdrop  
	{
		public function GradientBackdrop (c1:uint=0x002850, c2:uint=0x78B4F0, c3:uint=0x32281E, c4:uint=0x64503C, _skySqeeze:Number=3, _groundSqueeze:Number=3) {
			zenithColor = c1;
			skyColor = c2;
			groundColor = c3;
			nadirColor = c4;
			skySqeeze = _skySqeeze;
			groundSqeeze = _groundSqueeze;
		}
		
		/**
		* Upper sky color
		*/
		public var zenithColor:uint = 0x002850;
		public var zenithAlpha:Number = 1;
		/**
		* Sky color in the middle
		*/
		public var skyColor:uint = 0x78B4F0;
		public var skyAlpha:Number = 1;
		/**
		* Sky sqeeze from 0-1
		*/
		public var skySqeeze:Number = 0;
		/**
		* Ground sqeeze from 0-1
		*/
		public var groundSqeeze:Number = 0;
		/**
		* Middle ground color
		*/
		public var groundColor:uint = 0x32281E;
		public var groundAlpha:Number = 1;
		/**
		* Bottom ground color
		*/
		public var nadirColor:uint = 0x64503C;
		public var nadirAlpha:Number = 1;
		
		public override function drawToBitmap (view:View3d, lyr:Layer) :void {
			
			var bmp:BitmapData = lyr.bmp;
			
			var mrz:Transform3d = new Transform3d();
			
			if(view.scene.cam.transform.yAxis.y > 0) {
				mrz.rotationZ = -view.scene.cam.transform.rotationZ;
			}
			
			var gv:Matrix3d = new Matrix3d();
			gv.concatM4(mrz.gv, view.scene.cam.transform.gv, gv);
			
			var inv:Matrix3d = new Matrix3d();
			inv.a = gv.a;	inv.b = gv.e;	inv.c = gv.i;
			inv.e = gv.b;	inv.f = gv.f;	inv.g = gv.j;
			inv.i = gv.c;	inv.j = gv.g;	inv.k = gv.k;
			
			var x:Number = gv.m;	var y:Number = gv.n;	var z:Number = gv.o;
			
			inv.m = -(x * gv.a + y * gv.b + z * gv.c); 
			inv.n = -(x * gv.e + y * gv.f + z * gv.g);
			inv.o = -(x * gv.i + y * gv.j + z * gv.k);
			
			var mat:Matrix3d = view.scene.cam.pr;
			var cgvb:Number = inv.a*mat.b + inv.b*mat.f + inv.c*mat.j;
			var cgvc:Number = inv.a*mat.c + inv.b*mat.g + inv.c*mat.k;
			var cgvf:Number = inv.e*mat.b + inv.f*mat.f + inv.g*mat.j;
			var cgvg:Number = inv.e*mat.c + inv.f*mat.g + inv.g*mat.k;
			var cgvj:Number = inv.i*mat.b + inv.j*mat.f + inv.k*mat.j;
			var cgvk:Number = inv.i*mat.c + inv.j*mat.g + inv.k*mat.k;
			var cgvn:Number = inv.m*mat.b + inv.n*mat.f + inv.o*mat.j + mat.n;
			var cgvo:Number = inv.m*mat.c + inv.n*mat.g + inv.o*mat.k + mat.o;
			
			var tr:Transform3d = new Transform3d();
			tr.transform = view.scene.cam.transform.gv;

			var pi2:Number = Math.PI/2;
			var rz:Number = tr.rotationZ;
			var zy:Number = tr.zAxis.y;
			var rd:Number = zy*pi2;
			
			var mtx:Matrix = new Matrix();
			
			var fov:Number = view.scene.cam.fov;
			var fov2:Number = fov/2;
			
			var wt:Number = rd + fov2;
			var wb:Number = rd - fov2;
			var cx:Number = bmp.width/2;
			var cy:Number = bmp.height/2;
			
			var mw:Number = (Math.sqrt(cx*cx + cy*cy)*2 - Math.max(bmp.width, bmp.height))*4;
			var ofs:Number = mw/2;
			
			var sp:Sprite = new Sprite();
			var sqa:Number;
			var sqstart:Number;
			
			var fp:Vector3d = new Vector3d(0, 0, 0x7fffffff);
			
			var w:Number = cgvc*fp.x + cgvg*fp.y + cgvk*fp.z + cgvo + view.scene.cam._nearClipping;
			
			var xr:int;	var xg:int;	var xb:int; var xa:Number;
			var yr:int;	var yg:int;	var yb:int;
			var zr:int;	var zg:int;	var zb:int;
			var grs:Number=0;
			var gre:Number=255;
			var cnt:Number;
			var d:Number;
			var gp:Number;
			
			var cam:Camera3d= view.scene.cam;
			
			if(tr.yAxis.y < 0) {
				cnt = cam.s + (cgvb*fp.x + cgvf*fp.y + cgvj*fp.z + cgvn)/w * cam.s;
			}else{
				cnt = cam.s - (cgvb*fp.x + cgvf*fp.y + cgvj*fp.z + cgvn)/w * cam.s;
			}
			
			if(cnt > -ofs) {
				if(skySqeeze == 0) {
					sp.graphics.beginFill(skyColor, skyAlpha);
				}
				else{
					sqa = (Math.PI*4)/(skySqeeze+1);
					sqstart = sqa;
					
					xr = zenithColor >> 16 & 255;
					xg = zenithColor >> 8 & 255;
					xb = zenithColor & 255;
					
					yr = skyColor >> 16 & 255;
					yg = skyColor >> 8 & 255;
					yb = skyColor & 255;
					
					d = wt/sqstart;
					
					if(d>1) {
						xa = zenithAlpha;
						zr = xr;
						zg = xg;
						zb = xb;
						gp = cnt - (sqstart/wt*cnt) - 1;
						
						mtx.createGradientBox(bmp.width, cnt-gp, pi2, 0, gp);
						
						sp.graphics.beginGradientFill(
											GradientType.LINEAR, 
											[zr<<16 | zg<<8 | zb, 	skyColor],
											[xa, 	skyAlpha],
											[grs, 	gre], mtx
											);
					}
					else{
						d = 1-d;
						if(d < 1) {
							
							xa = zenithAlpha + (skyAlpha-zenithAlpha) * d;
							zr = xr + (yr-xr)*d;
							zg = xg + (yg-xg)*d;
							zb = xb + (yb-xb)*d;
							mtx.createGradientBox(bmp.width, cnt, pi2, 0, 0);
							
							sp.graphics.beginGradientFill(
											GradientType.LINEAR, 
											[zr<<16 | zg<<8 | zb, 	skyColor],
											[xa, 	skyAlpha],
											[grs, 	gre], mtx
											);
						}
						else{
							// SKY ONLY
							sp.graphics.beginFill(skyColor, skyAlpha);
						}
					}
				}
				
				// Draw Sky Rect
				sp.graphics.drawRect(-ofs, -ofs, bmp.width + mw, cnt + ofs);
				sp.graphics.endFill();
			}
			
			if(cnt < bmp.height+ofs) {
				if(groundSqeeze == 0) 
				{
					sp.graphics.beginFill(groundColor, groundAlpha);
				}
				else
				{
					sqa = (Math.PI*4)/(groundSqeeze+1);
					sqstart = -sqa;
					
					// gradient ground
						
					xr = groundColor >> 16 & 255;
					xg = groundColor >> 8 & 255;
					xb = groundColor & 255;
					
					yr = nadirColor >> 16 & 255;
					yg = nadirColor >> 8 & 255;
					yb = nadirColor & 255;
					
					d = wb/sqstart;
					
					if(d > 1) {
						
						xa = nadirAlpha;
						zr = yr;
						zg = yg;
						zb = yb;
						
						var bth:Number = bmp.width - cnt;
						gp = bth - (sqstart/wb*bth);
						mtx.createGradientBox(bmp.width, bth-gp, pi2, 0, cnt);
						
						sp.graphics.beginGradientFill(
											GradientType.LINEAR, 
											[groundColor, zr<<16 | zg<<8 | zb],
											[groundAlpha, xa],
											[grs, 	gre], mtx
											);
					}
					else
					{
						if(d > 0) {
							
							xa = groundAlpha + (nadirAlpha-groundAlpha) * d;
							zr = xr + (yr-xr)*d;
							zg = xg + (yg-xg)*d;
							zb = xb + (yb-xb)*d;
							
							mtx.createGradientBox(bmp.width, (bmp.height+ofs)-cnt, pi2, 0, cnt);
							
							sp.graphics.beginGradientFill(
											GradientType.LINEAR, 
											[groundColor, zr<<16 | zg<<8 | zb],
											[groundAlpha, xa],
											[grs, 	gre], mtx
											);
						}
						else
						{
							// GROUND ONLY
							sp.graphics.beginFill(groundColor, groundAlpha);
						}
					}
				}
				sp.graphics.drawRect(-ofs, cnt, bmp.width + mw, (bmp.height-cnt) + ofs);
				sp.graphics.endFill();
			}
			var mt2:Matrix = new Matrix();
			
			mt2.translate(-(bmp.width)/2, -(bmp.height)/2);
			mt2.rotate(rz);
			mt2.translate((bmp.width)/2, (bmp.height)/2);
			
			bmp.draw(sp, mt2);
		}
	
	}
}